/**************************************************
 * Filename: DataSourceImpl.java
 * Version: v1.0
 * CreatedDate: 2011-5-5
 * Copyright (C) 2011 By cafebabe.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses/.
 *
 * If you would like to negotiate alternate licensing terms, you may do
 * so by contacting the author: talentyao@foxmail.com
 ***************************************************/

package com.ywh.dbpools;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.concurrent.DelayQueue;

import javax.sql.DataSource;

/**
 * 数据源实现类
 * 
 * @author cafebabe
 * @since 2011-5-5
 * @version 1.0
 */
public class DataSourceImpl implements DataSource {

	private DelayQueue<ConnectionProxy> dbPools = new DelayQueue<ConnectionProxy>();

	private final ConnectionParameter connParam; // 连接的参数

	private boolean isEnd;

	public DataSourceImpl(ConnectionParameter connParam) {
		this.connParam = connParam;
		// 初始化连接池
		try {
			Class.forName(connParam.getDriver());
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		for (int i = 0; i < connParam.getMinConnection(); i++) {
			try {
				dbPools.add(createNewConnnection());
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		ConnectionManeage maneage = new ConnectionManeage();
		maneage.setDaemon(true);
		maneage.start();

	}

	private class ConnectionManeage extends Thread {
		public void run() {
			while (!isEnd) {
				System.out.println(connParam.getName() + "连接数量："
						+ dbPools.size());
				if (dbPools.size() > connParam.getMinConnection()) {
					try {
						ConnectionProxy connProxy = dbPools.take();
						System.out.println(connProxy.getConn());
						connProxy.close();
						System.err.println(connParam.getName() + "成功管理一次！size="
								+ dbPools.size());
					} catch (InterruptedException e) {
						e.printStackTrace();
					} catch (SQLException e) {
						e.printStackTrace();
					}
				}
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

		}
	}

	private Connection getFreeConnection() throws SQLException {
		Connection conn = null;
		for (ConnectionProxy connProxy : dbPools) {
			if (!connProxy.isUsing()) {
				conn = connProxy.getConn();
				System.out.println(connParam.getName() + "成功获的连接,size="
						+ dbPools.size());
				break;
			}
		}
		return conn;
	}

	/**
	 * 获取数据库连接
	 * <p>
	 * override 方法
	 * 
	 * @see javax.sql.DataSource#getConnection()
	 */
	public synchronized Connection getConnection() throws SQLException {
		Connection conn = getFreeConnection();
		if (conn == null) {
			if (dbPools.size() >= connParam.getMaxConnection()) {
				try {
					System.err.println(connParam.getName() + "获取连接时等待"
							+ connParam.getWaitTime() + "毫秒...");
					// 等待指定毫秒后看是否有空闲连接
					Thread.sleep(connParam.getWaitTime());
				} catch (Exception e) {
					e.printStackTrace();
				}
				conn = getFreeConnection();
				if (conn == null) {
					System.out.println(connParam.getName() + "暂时无法获取连接！");
				}
			} else { // 没有超过连接数，重新获取一个数据库的连接
				conn = createNewConnnection().getConn();
			}
		}
		return conn;
	}

	/**
	 * 功能描述 创建新的代理连接
	 * <p>
	 * 
	 * @return 创建的代理连接
	 * @throws SQLException
	 * @throws
	 */
	private ConnectionProxy createNewConnnection() throws SQLException {
		Connection conn = DriverManager.getConnection(connParam.getUrl(),
				connParam.getUser(), connParam.getPassword());
		// 代理将要返回的连接对象
		ConnectionProxy connProxy = new ConnectionProxy(conn,
				connParam.getTimeoutValue());
		dbPools.add(connProxy);
		System.err.println(connParam.getName() + "当前池中的连接数：" + dbPools.size());
		return connProxy;
	}

	public Connection getConnection(String arg0, String arg1)
			throws SQLException {
		// TODO Auto-generated method stub
		return getConnection();
	}

	public PrintWriter getLogWriter() throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	public int getLoginTimeout() throws SQLException {
		// TODO Auto-generated method stub
		return 0;
	}

	public void setLogWriter(PrintWriter arg0) throws SQLException {
		// TODO Auto-generated method stub

	}

	public void setLoginTimeout(int arg0) throws SQLException {
		// TODO Auto-generated method stub

	}

	public boolean isWrapperFor(Class<?> arg0) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	public <T> T unwrap(Class<T> arg0) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * 关闭该连接池中的所有数据库连接 并停止后台管理线程
	 * 
	 * @throws SQLException
	 */
	public void close() throws SQLException {
		isEnd = true;
		for (ConnectionProxy connProxy : dbPools) {
			connProxy.close();
		}
	}
}
